package miggy.cpu.instructions.bitshift;

import miggy.api.cpu.Size;
import miggy.api.cpu.DecodedInstruction;
import miggy.cpu.DecodedInstructionImpl;
import miggy.SystemModel;
import miggy.api.cpu.CpuFlag;
import miggy.api.cpu.DecodedInstruction;
import miggy.cpu.operands.OperandFactory;

// $Revision: 21 $
public class ROXR
{
	public final int execute(int opcode, Size size)
	{
		int shift;

		if((opcode & 0x0020) == 0)
		{
			//immediate data with shift count
			shift = (opcode & 0x0e00) >> 9;
			if(shift == 0)
				shift = 8;
		}
		else
		{
			//Dn/Dn
			shift = SystemModel.CPU.getDataRegister((opcode & 0x0e00) >> 9);
		}

		int dstreg = opcode & 0x0007;
		int dstval = SystemModel.CPU.getDataRegister(dstreg);
		int odstval = dstval;

		dstval &= size.mask();

		SystemModel.CPU.clrFlag(CpuFlag.V);

		if(shift > 0)
		{
			SystemModel.CPU.clrFlag(CpuFlag.C);

			int hi = (dstval << 1) | (SystemModel.CPU.isSet(CpuFlag.X) ? 1 : 0);
			hi <<= (size.bitSize() - shift);
			shift--;
			dstval >>>= shift;
			int carry = dstval & 1;
			dstval >>>= 1;
			dstval |= hi;
			dstval &= size.mask();

			if(carry != 0)
			{
				SystemModel.CPU.setFlag(CpuFlag.C);
				SystemModel.CPU.setFlag(CpuFlag.X);
			}
			else
			{
				SystemModel.CPU.clrFlag(CpuFlag.C);
				SystemModel.CPU.clrFlag(CpuFlag.X);
			}
		}
		else
		{
			//copy x flag into c if no shift value
			if(SystemModel.CPU.isSet(CpuFlag.X))
			{
				SystemModel.CPU.setFlag(CpuFlag.C);
			}
			else
			{
				SystemModel.CPU.clrFlag(CpuFlag.C);
			}
		}

		if(dstval == 0)
		{
			SystemModel.CPU.setFlag(CpuFlag.Z);
		}
		else
		{
			SystemModel.CPU.clrFlag(CpuFlag.Z);
			if((dstval & size.msb()) != 0)
			{
				SystemModel.CPU.setFlag(CpuFlag.N);
			}
			else
			{
				SystemModel.CPU.clrFlag(CpuFlag.N);
			}
		}

		odstval &= ~(size.mask());
		SystemModel.CPU.setDataRegister(dstreg, odstval | dstval);
		return (size == Size.Long ? 8 : 6) + (shift << 1);
	}

	public final DecodedInstruction decode(int address, int opcode, Size size)
	{
		DecodedInstructionImpl di = new DecodedInstructionImpl("roxr" + size.ext(), opcode, address, size);

		if((opcode & 0x0020) == 0)
		{
			//immediate data with shift count
			int shift = (opcode & 0x0e00) >> 9;
			if(shift == 0)
				shift = 8;

			di.setSrc(OperandFactory.literal(shift));
			di.setDst(OperandFactory.dataReg(opcode & 0x0007));
		}
		else
		{
			//Dn/Dn
			di.setSrc(OperandFactory.dataReg((opcode & 0x0e00) >> 9));
			di.setDst(OperandFactory.dataReg(opcode & 0x007));
		}

		return di;
	}
}
